﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

using Includes;

namespace SyncroneModule
{
   /// <summary>
   /// Control class, handling the overall program flow of the syncrone module
   /// </summary>
   public class SyncroneModule
   {
      // Intervall in which the checks are conducted (in seconds)
      const int INTERVALL = 5*60;

      static void Main(string[] args)
      {
         // Run directly after start
         timedEvent(new Object(), new EventArgs());
         
         // Set up timed test routine
         Timer t1 = new Timer();
         t1.Interval  = (INTERVALL * 1000);
         t1.Elapsed  += new ElapsedEventHandler(timedEvent);
         t1.AutoReset = true;
         t1.Start();

         while(true)
         {
            System.Threading.Thread.Sleep((int)(INTERVALL * 30000));
         }
      }

      static bool running = false;

      // Doing the actual work in timed intervalls
      private static void timedEvent(Object eventSource, EventArgs eventArguments)
      {

         // If Synchrone thread is already running ignore, this will cause unintended
         // behaviour though!
         if (running)
         {
            Console.WriteLine("CRITICAL! PROCESSING TIME NOT SUFFICIENT!, IGNORING RUN!");
            return;
         }

         // Block additional worker threads
         running = true;

         DateTime start   = DateTime.Now;
         DateTime finish  = DateTime.Now;
         IPersistSync per = new PersistSync();
         CallInfoSync[] currentResultset;
         String[] informed;

         Console.WriteLine("Running check  @ {0}",start);

         // Mark everyone as informed who was sucessfully informed in the last iteration
         // (Async control translates status sms to files)
         if(System.IO.Directory.Exists("Info"))
         {
            informed = System.IO.Directory.GetFiles("Info","+*");

            foreach (String curInfo in informed)
            {
               // Get number
               String callerID = System.IO.Path.GetFileNameWithoutExtension(curInfo);
            
               // Set info flag
               Flags tmp = per.getFlags(callerID);
               tmp.info = true;
               per.setFlags(callerID,tmp);

               Console.Write("{0} has been marked as informed", callerID);

               // Delete infofile
               try
               {
                  System.IO.File.Delete(curInfo);
                  Console.WriteLine("(File deleted)");
               }
               catch (System.IO.IOException)
               {
                  Console.WriteLine("(File _NOT_ deleted (Probably in use))");
               }

            }
         }
         Console.WriteLine("#Informed flags for last iteration calling processed#");


         // Clear all KR flags for checks that become current in less than 10 minutes
         per.clearInformedFlags(10*60);
         Console.WriteLine("#Informed flags of patients with impending check time cleared#");


         // Get everyone whose data has not been submitted for 60 minutes
         // And has not yet been informed
         currentResultset = per.getTelListInfoVeryLate(60*60);

         foreach(CallInfoSync curRes in currentResultset)
         {
            VoiceCall tmp = new VoiceCall();
            tmp.receipientNumber = curRes.number;
            tmp.patientName      = curRes.name;
            tmp.senderNumber     = "0123456789";
            tmp.fileID           = "IZK0001";
            tmp.alternative      = Messages.IZK0001.Replace("<Name des Patienten>", curRes.name);

            // Try to reach next of kin
            Console.WriteLine("Calling {0}'s NOK => {1}", curRes.name, curRes.number);
            TropoWrapper.sendVoiceCall(tmp);

            // If person has been called, mark as informed            
            Flags flags = per.getFlags(curRes.number);
            flags.info = true;
            per.setFlags(curRes.number, flags);
         }

         Console.WriteLine("#People who have not submitted for 60min Processed#");

         // Get everyone who should have submitted his/her data 30 min ago
         // And has not yet been informed about them missing
         currentResultset = per.getTelListInfoLate(30*60);

         foreach (CallInfoSync curRes in currentResultset)
         {
            VoiceCall tmp = new VoiceCall();
            tmp.receipientNumber = curRes.number;
            tmp.patientName      = curRes.name;
            tmp.senderNumber     = "0123456789";
            tmp.fileID           = "IP0001";
            tmp.alternative      = Messages.IP0001.Replace("<Name des Patienten>", curRes.name);

            Console.WriteLine("Calling {0} => {1}",curRes.name, curRes.number);

            // If person has been reached, mark as informed
            if (!TropoWrapper.sendVoiceCall(tmp))
            {
               Console.WriteLine("Initializing call ({0}) failed",tmp.receipientNumber);

            // Informing is done using a system response SMS
/*
               Flags flags = per.getFlags(curRes.number);
               flags.info = true;
               per.setFlags(curRes.number, flags);
*/
            }
         }

         Console.WriteLine("#People who have not submitted for 30min Processed#");

         // Get everyone whos KR flag has been set 3 hours ago
         currentResultset = per.getTelListKR(3 * 60 * 60);

         foreach (CallInfoSync curRes in currentResultset)
         {
            VoiceCall tmp = new VoiceCall();
            tmp.receipientNumber = curRes.number;
            tmp.patientName      = curRes.name;
            tmp.senderNumber     = "0123456789";
            tmp.fileID           = "IZK0001";
            tmp.alternative      = Messages.IZK0001.Replace("<Name des Patienten>", curRes.name);

            // If person has been called, mark as informed (whether he picked up or not)
            Console.WriteLine("Calling {0}'s NOK => {1}", curRes.name, curRes.number);
            if (TropoWrapper.sendVoiceCall(tmp))
            {
               Flags flags = per.getFlags(curRes.number);
               flags.kr = false;
               per.setFlags(curRes.number, flags);
            }
         }

         Console.WriteLine("#KR expectancy processed#");

         // Allow next time to execute
         running = false; 

         Console.WriteLine("Finished check @ {0}, taking {1} seconds\n", DateTime.Now, finish.Subtract(start).TotalSeconds);
      }
   }
}
